home *** CD-ROM | disk | FTP | other *** search
/ Aminet 49 / Aminet 49 (2002)(GTI - Schatztruhe)[!][Jun 2002].iso / Aminet / util / sys / AmberRAM.lha / AmberRAM / Source / filesystem.c < prev    next >
C/C++ Source or Header  |  2002-02-27  |  28KB  |  1,359 lines

  1. /*
  2.  
  3. File: filesystem.c
  4. Author: Neil Cafferkey
  5. Copyright (C) 2001-2002 Neil Cafferkey
  6.  
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  20. MA 02111-1307, USA.
  21.  
  22. */
  23.  
  24.  
  25. #include "handler_protos.h"
  26.  
  27.  
  28.  
  29. /****i* ram.handler/CreateObject *******************************************
  30. *
  31. *   NAME
  32. *    CreateObject --
  33. *
  34. *   SYNOPSIS
  35. *    object = CreateObject(handler,name,type,
  36. *        parent)
  37. *
  38. *    struct Object *CreateObject(struct Handler *,TEXT *,BYTE,
  39. *        struct Object *);
  40. *
  41. *   FUNCTION
  42. *
  43. *   INPUTS
  44. *
  45. *   RESULT
  46. *
  47. *   EXAMPLE
  48. *
  49. *   NOTES
  50. *
  51. *   BUGS
  52. *
  53. *   SEE ALSO
  54. *
  55. ****************************************************************************
  56. *
  57. */
  58.  
  59. struct Object *CreateObject(struct Handler *handler,const TEXT *name,
  60.    BYTE type,struct Object *parent)
  61. {
  62.    struct Object *object;
  63.    LONG error;
  64.    UPINT block_count;
  65.  
  66.    /* Check for an existing object with the same name */
  67.  
  68.    error=0;
  69.    object=NULL;
  70.    if(parent!=NULL)
  71.    {
  72.       parent=GetRealObject(parent);
  73.       object=(APTR)FindNameNoCase((struct List *)&parent->elements,name);
  74.    }
  75.  
  76.    /* Create a new object structure */
  77.  
  78.    if(object==NULL)
  79.    {
  80.       object=AllocMem(sizeof(struct Object),MEMF_CLEAR);
  81.       if(object==NULL)
  82.          error=ERROR_DISK_FULL;
  83.  
  84.       if(error==0)
  85.       {
  86.          block_count=MEMBLOCKS(sizeof(struct Object));
  87.          object->block_count=MEMBLOCKS(sizeof(struct Object));
  88.          handler->block_count+=MEMBLOCKS(sizeof(struct Object));
  89.  
  90.          NewList((struct List *)&object->elements);
  91.          ((struct Node *)object)->ln_Pri=type;
  92.          object->parent=parent;
  93.          DateStamp(&object->date);
  94.  
  95.          if(name!=NULL)
  96.          {
  97.             name=FilePart(name);
  98.             if(!SetName(handler,object,name))
  99.                error=IoErr();
  100.          }
  101.  
  102.          if(parent!=NULL)
  103.          {
  104.             AddTail((struct List *)&parent->elements,(struct Node *)object);
  105.             CopyMem(&object->date,&parent->date,sizeof(struct DateStamp));
  106.          }
  107.       }
  108.    }
  109.    else
  110.    {
  111.       error=ERROR_OBJECT_EXISTS;
  112.    }
  113.  
  114.    if(error==0)
  115.       MatchNotifyRequests(handler);
  116.  
  117.    if(error!=0)
  118.    {
  119.       DeleteObject(handler,object);
  120.       object=NULL;
  121.    }
  122.  
  123.    /* Return the new object */
  124.  
  125.    SetIoErr(error);
  126.    return object;
  127. }
  128.  
  129.  
  130.  
  131. /****i* ram.handler/DeleteObject *******************************************
  132. *
  133. *   NAME
  134. *    DeleteObject --
  135. *
  136. *   SYNOPSIS
  137. *    success = DeleteObject(handler,object)
  138. *
  139. *    BOOL DeleteObject(struct Handler *,struct Object *);
  140. *
  141. *   FUNCTION
  142. *
  143. *   INPUTS
  144. *    object - the object to be deleted, or NULL for no action.
  145. *
  146. *   RESULT
  147. *    success - success indicator.
  148. *
  149. *   EXAMPLE
  150. *
  151. *   NOTES
  152. *
  153. *   BUGS
  154. *
  155. *   SEE ALSO
  156. *
  157. ****************************************************************************
  158. *
  159. */
  160.  
  161. BOOL DeleteObject(struct Handler *handler,struct Object *object)
  162. {
  163.    LONG error=0;
  164.    BYTE object_type;
  165.    struct Lock *lock;
  166.    struct Block *block;
  167.    struct MinNode *node;
  168.    struct Object *real_object,*master_link,*heir,*dir;
  169.    PINT block_diff;
  170.  
  171.    if(object!=NULL)
  172.    {
  173.       real_object=GetRealObject(object);
  174.  
  175.       /* Check for a non-empty, unlinked directory */
  176.  
  177.       object_type=((struct Node *)object)->ln_Pri;
  178.       if((object_type==ST_USERDIR)&&(object->hard_link.mln_Succ==NULL)
  179.          &&!IsListEmpty((struct List *)&object->elements))
  180.          error=ERROR_DIRECTORY_NOT_EMPTY;
  181.  
  182.       /* Ensure the object isn't in use */
  183.  
  184.       lock=LockObject(handler,object,ACCESS_WRITE);
  185.       if(lock==NULL)
  186.          error=IoErr();
  187.       CmdFreeLock(handler,lock);
  188.  
  189.       if(error==0)
  190.       {
  191.          /* Remove the object from its directory */
  192.  
  193.          if(object->parent!=NULL)
  194.             Remove((struct Node *)object);
  195.  
  196.          /* Delete a hard link */
  197.  
  198.          if((object_type==ST_LINKFILE)||(object_type==ST_LINKDIR))
  199.          {
  200.             node=real_object->hard_link.mln_Succ;
  201.             master_link=HARDLINK(node);
  202.             Remove((APTR)&object->hard_link);
  203.             if(object==master_link)
  204.             {
  205.                node=node->mln_Succ;
  206.                if(node->mln_Succ!=NULL)
  207.                {
  208.                   master_link=HARDLINK(node);
  209.                   while((node=(APTR)RemHead((APTR)&object->elements))!=NULL)
  210.                      AddTail((APTR)&master_link->elements,(APTR)node);
  211.                }
  212.                else
  213.                {
  214.                   real_object->hard_link.mln_Succ=NULL;
  215.                   real_object->hard_link.mln_Pred=NULL;
  216.                }
  217.             }
  218.          }
  219.  
  220.          /* Delete a linked object */
  221.  
  222.          else if((node=object->hard_link.mln_Succ)!=NULL)
  223.          {
  224.             master_link=HARDLINK(node);
  225.             heir=HARDLINK(RemTail((APTR)&master_link->elements));
  226.  
  227.             /* Swap names and comments */
  228.  
  229.             block_diff=SwapStrings(&((struct Node *)heir)->ln_Name,
  230.                &((struct Node *)object)->ln_Name);
  231.             block_diff+=SwapStrings(&heir->comment,&object->comment);
  232.             object->block_count+=block_diff;
  233.             heir->block_count-=block_diff;
  234.  
  235.             /* Put object in its new directory */
  236.  
  237.             object->parent=heir->parent;
  238.             AddTail((APTR)&object->parent->elements,(APTR)object);
  239.  
  240.             if(heir==master_link)
  241.             {
  242.                real_object->hard_link.mln_Succ=NULL;
  243.                real_object->hard_link.mln_Pred=NULL;
  244.             }
  245.  
  246.             /* Prepare to destroy "heir" link */
  247.  
  248.             Remove((APTR)heir);
  249.             object=heir;
  250.          }
  251.  
  252.          /* Delete the root directory and all other objects */
  253.  
  254.          else if(object_type==ST_ROOT)
  255.          {
  256.             dir=object;
  257.  
  258.             while(dir!=NULL)
  259.             {
  260.                object=(APTR)RemHead((struct List *)&dir->elements);
  261.  
  262.                if(object==NULL)
  263.                {
  264.                   object=dir;
  265.                   dir=dir->parent;
  266.                   if(dir!=NULL)
  267.                      DeleteObject(handler,object);
  268.                }
  269.                else if(((struct Node *)object)->ln_Pri==ST_USERDIR)
  270.                {
  271.                   dir=object;
  272.                }
  273.                else
  274.                {
  275.                   DeleteObject(handler,object);
  276.                }
  277.             }
  278.          }
  279.  
  280.          /* Delete an unlinked object */
  281.  
  282.          else
  283.          {
  284.             /* Remove all blocks if the object is a file */
  285.  
  286.             while((block=(APTR)RemTail((struct List *)&object->elements))
  287.                !=NULL)
  288.                FreeMem(block,sizeof(struct Block)+block->length);
  289.          }
  290.  
  291.          /* Free object's memory */
  292.  
  293.          SetString(&((struct Node *)object)->ln_Name,NULL);
  294.          SetString(&object->comment,NULL);
  295.          handler->block_count-=object->block_count;
  296.          FreeMem(object,sizeof(struct Object));
  297.       }
  298.    }
  299.  
  300.    /* Return result */
  301.  
  302.    SetIoErr(error);
  303.    return error==0;
  304. }
  305.  
  306.  
  307.  
  308. /****i* ram.handler/GetObject **********************************************
  309. *
  310. *   NAME
  311. *    GetObject --
  312. *
  313. *   SYNOPSIS
  314. *    object = GetObject(handler,lock,name,
  315. *        parent)
  316. *
  317. *    struct Object *GetObject(struct Handler *,struct Lock *,TEXT *,
  318. *        struct Object **);
  319. *
  320. *   FUNCTION
  321. *
  322. *   INPUTS
  323. *    lock - .
  324. *    name - .
  325. *    parent - .
  326. *
  327. *   RESULT
  328. *    object - The located object.
  329. *
  330. *   EXAMPLE
  331. *
  332. *   NOTES
  333. *
  334. *   BUGS
  335. *
  336. *   SEE ALSO
  337. *
  338. ****************************************************************************
  339. *
  340. */
  341.  
  342. struct Object *GetObject(struct Handler *handler,
  343.    struct Lock *lock,const TEXT *name,struct Object **parent)
  344. {
  345.    const TEXT *p;
  346.    TEXT ch,buffer[256];
  347.    PINT pos;
  348.    struct Object *object,*old_object;
  349.  
  350.    old_object=NULL;
  351.    for(ch=*(p=name);(ch!=':')&&(ch!='\0');ch=*(++p));
  352.    if(ch==':')
  353.       name=p+1;
  354.  
  355.    /* Get object referenced by lock */
  356.  
  357.    lock=FixLock(handler,lock);
  358.    object=(APTR)((struct FileLock *)lock)->fl_Key;
  359.  
  360.    /* Traverse textual portion of path */
  361.  
  362.    pos=0;
  363.    while((pos!=-1)&&(object!=NULL))
  364.    {
  365.       pos=SplitName(name,'/',buffer,pos,256);
  366.       if(*buffer!='\0')
  367.       {
  368.          old_object=object;
  369.          if(((struct Node *)object)->ln_Pri>0)
  370.          {
  371.             object=GetRealObject(object);
  372.             object=(struct Object *)
  373.                FindNameNoCase((struct List *)&object->elements,buffer);
  374.          }
  375.          else
  376.          {
  377.             object=NULL;
  378.             old_object=NULL;
  379.          }
  380.       }
  381.       else if(pos!=-1)
  382.       {
  383.          object=object->parent;
  384.       }
  385.    }
  386.  
  387.    /* Record the parent directory of the supplied path, if it exists */
  388.  
  389.    if(parent!=NULL)
  390.    {
  391.       if(pos==-1)
  392.          *parent=old_object;
  393.       else
  394.          *parent=NULL;
  395.    }
  396.  
  397.    /* Return the located object */
  398.  
  399.    SetIoErr(ERROR_OBJECT_NOT_FOUND);
  400.    return object;
  401. }
  402.  
  403.  
  404.  
  405. /****i* ram.handler/ChangeFileSize *****************************************
  406. *
  407. *   NAME
  408. *    ChangeFileSize --
  409. *
  410. *   SYNOPSIS
  411. *    new_size = ChangeFileSize(handler,opening,offset,
  412. *       mode)
  413. *
  414. *    PINT ChangeFileSize(struct Handler *,struct Opening *,PINT,
  415. *       LONG);
  416. *
  417. *   FUNCTION
  418. *    If there is not enough space for the requested size, the file size
  419. *    will remain at its initial value and -1 will be returned.
  420. *
  421. *
  422. *
  423. *
  424. *   INPUTS
  425. *
  426. *   RESULT
  427. *
  428. *   EXAMPLE
  429. *
  430. *   NOTES
  431. *
  432. *   BUGS
  433. *
  434. *   SEE ALSO
  435. *
  436. ****************************************************************************
  437. *
  438. */
  439.  
  440. PINT ChangeFileSize(struct Handler *handler,struct Opening *opening,
  441.    PINT offset,LONG mode)
  442. {
  443.    PINT length,new_length,remainder,end_length,full_length;
  444.    UPINT diff,old_pos,block_count;
  445.    struct Block *block,*end_block;
  446.    struct Object *file;
  447.    LONG error=0;
  448.  
  449.    /* Get origin */
  450.  
  451.    file=opening->file;
  452.  
  453.    if(mode==OFFSET_BEGINNING)
  454.       new_length=0;
  455.    else if(mode==OFFSET_CURRENT)
  456.       new_length=opening->pos;
  457.    else
  458.       new_length=file->length;
  459.  
  460.    if(-offset>new_length)
  461.    {
  462.       SetIoErr(ERROR_SEEK_ERROR);
  463.       return -1;
  464.    }
  465.  
  466.    new_length+=offset;
  467.    length=file->length;
  468.    block_count=file->block_count;
  469.  
  470.    old_pos=opening->pos;
  471.  
  472.    full_length=length;
  473.    end_length=file->end_length;
  474.    block=(struct Block *)file->elements.mlh_TailPred;
  475.    if(end_length!=0)
  476.    {
  477.       full_length+=block->length-end_length;
  478.    }
  479.  
  480.    if(new_length>length)
  481.    {
  482.       /* Add the required number of data bytes */
  483.  
  484.       remainder=new_length-full_length;
  485.       end_length-=remainder;
  486.  
  487.       while(remainder>0)
  488.       {
  489.          block=AddDataBlock(handler,file,remainder);
  490.          if(block!=NULL)
  491.          {
  492.             end_length=remainder;
  493.             remainder-=block->length;
  494.          }
  495.          else
  496.             remainder=0;
  497.       }
  498.  
  499.       /* Remove new blocks upon failure */
  500.  
  501.       if(block==NULL)
  502.       {
  503.          new_length=-1;
  504.          error=IoErr();
  505.          ChangeFileSize(handler,opening,length,OFFSET_BEGINNING);
  506.       }
  507.       else
  508.          file->end_length=end_length;
  509.    }
  510.    else if(length!=new_length)
  511.    {
  512.       /* Remove surplus blocks from the file */
  513.  
  514.       block=NULL;
  515.       while(full_length>new_length)
  516.       {
  517.          FreeDataBlock(file,block);
  518.          block=(APTR)RemTail((APTR)&file->elements);
  519.          full_length-=block->length;
  520.       }
  521.       end_block=(APTR)file->elements.mlh_TailPred;
  522.       if((APTR)end_block!=(APTR)&file->elements)
  523.          end_length=end_block->length;
  524.       else
  525.          end_length=0;
  526.       file->end_length=end_length;
  527.  
  528.       /* Allocate a suitably sized end block and copy old data to it */
  529.  
  530.       diff=new_length-full_length;
  531.       file->length=full_length;
  532.       CmdSeek(opening,0,OFFSET_END);
  533.  
  534.       if(ChangeFileSize(handler,opening,diff,OFFSET_END)!=-1)
  535.       {
  536.          WriteData(handler,opening,((UBYTE *)block)+sizeof(struct Block),
  537.             diff);
  538.          FreeDataBlock(file,block);
  539.       }
  540.       else
  541.          AddTail((struct List *)&file->elements,(APTR)block);
  542.  
  543.       /* Ensure opening's position isn't past new EOF */
  544.  
  545.       if(opening->pos>new_length)
  546.       {
  547.          opening->block=(APTR)&file->elements.mlh_Tail;
  548.          opening->block_pos=0;
  549.          opening->pos=new_length;
  550.       }
  551.    }
  552.  
  553.    /* Re-establish old seek position */
  554.  
  555.    CmdSeek(opening,old_pos,OFFSET_BEGINNING);
  556.  
  557.    /* Store new file size */
  558.  
  559.    if(new_length!=-1)
  560.       file->length=new_length;
  561.    handler->block_count+=file->block_count-block_count;
  562.  
  563.    SetIoErr(error);
  564.    return new_length;
  565. }
  566.  
  567.  
  568.  
  569. /****i* ram.handler/ReadData ***********************************************
  570. *
  571. *   NAME
  572. *    ReadData --
  573. *
  574. *   SYNOPSIS
  575. *    read_length = ReadData(opening,buffer,length)
  576. *
  577. *    UPINT ReadData(struct Opening *,UBYTE *,UPINT);
  578. *
  579. *   FUNCTION
  580. *
  581. *   INPUTS
  582. *
  583. *   RESULT
  584. *
  585. *   EXAMPLE
  586. *
  587. *   NOTES
  588. *
  589. *   BUGS
  590. *
  591. *   SEE ALSO
  592. *
  593. ****************************************************************************
  594. *
  595. */
  596.  
  597. UPINT ReadData(struct Opening *opening,UBYTE *buffer,UPINT length)
  598. {
  599.    struct Block *block;
  600.    UPINT block_pos,block_length,read_length=0,remainder;
  601.    struct Object *file;
  602.  
  603.    /* Fill buffer until request has been fulfilled or EOF is reached */
  604.  
  605.    block=opening->block;
  606.    block_pos=opening->block_pos;
  607.    file=opening->file;
  608.  
  609.    remainder=file->length-opening->pos;
  610.    if(length>remainder)
  611.       length=remainder;
  612.    remainder=length;
  613.  
  614.  
  615. #if 0
  616.    ahead=file->length-opening->pos;
  617.    if(length>ahead)
  618.       length=ahead;
  619.    length=remainder;
  620.  
  621.  
  622.    if(opening->pos+length>file->length)
  623.       length=file->length-opening->pos;
  624.    remainder=length;
  625.  
  626.  
  627.    if(opening->pos+length>file->length)
  628.       length=file->length-opening->pos;
  629.    remainder=length;
  630. #endif
  631.  
  632.    while(remainder>0)
  633.    {
  634.       /* Get number of remaining valid bytes in this block */
  635.  
  636.       block_length=GetBlockLength(file,block);
  637.       block_length-=block_pos;
  638.  
  639.       /* Copy block contents into the caller's buffer */
  640.  
  641.       read_length=MIN(remainder,block_length);
  642.       CopyMem(((UBYTE *)block)+sizeof(struct Block)+block_pos,buffer,
  643.          read_length);
  644.       remainder-=read_length;
  645.       buffer+=read_length;
  646.  
  647.       /* Get next block */
  648.  
  649.       if(read_length==block_length)
  650.       {
  651.          block=(struct Block *)((struct MinNode *)block)->mln_Succ;
  652.          block_pos=0;
  653.          read_length=0;
  654.       }
  655.    }
  656.  
  657.    /* Record new position for next access */
  658.  
  659.    opening->block=block;
  660.    opening->block_pos=block_pos+read_length;
  661.    opening->pos+=length;
  662.  
  663.    /* Return number of bytes read */
  664.  
  665.    return length;
  666. }
  667.  
  668.  
  669.  
  670. /****i* ram.handler/WriteData **********************************************
  671. *
  672. *   NAME
  673. *    WriteData --
  674. *
  675. *   SYNOPSIS
  676. *    write_length = WriteData(handler,opening,buffer,length)
  677. *
  678. *    UPINT WriteData(struct Handler *,struct Opening *,UBYTE *,UPINT);
  679. *
  680. *   FUNCTION
  681. *
  682. *   INPUTS
  683. *
  684. *   RESULT
  685. *
  686. *   EXAMPLE
  687. *
  688. *   NOTES
  689. *
  690. *   BUGS
  691. *
  692. *   SEE ALSO
  693. *
  694. ****************************************************************************
  695. *
  696. */
  697.  
  698. UPINT WriteData(struct Handler *handler,struct Opening *opening,
  699.    UBYTE *buffer,UPINT length)
  700. {
  701.    struct Block *block,*end_block;
  702.    struct Object *file;
  703.    UPINT block_pos,block_length,write_length,remainder=length,block_count,
  704.       file_length,pos;
  705.    LONG error=0;
  706.  
  707.    file=opening->file;
  708.    file_length=file->length;
  709.    block_count=file->block_count;
  710.    pos=opening->pos;
  711.    block=opening->block;
  712.    block_pos=opening->block_pos;
  713.  
  714.    /* If at EOF, go back to use up any space left in last block */
  715.  
  716.    if((pos==file_length)&&(pos!=0))
  717.    {
  718.       block=(struct Block *)((struct MinNode *)block)->mln_Pred;
  719.       block_pos=file->end_length;
  720.    }
  721.  
  722.    while((remainder>0)&&(block!=NULL)&&(error==0))
  723.    {
  724.       /* Add another block to the file if required */
  725.  
  726.       if(((struct MinNode *)block)->mln_Succ==NULL)
  727.       {
  728.          block=AddDataBlock(handler,opening->file,remainder);
  729.          file->end_length=0;
  730.       }
  731.  
  732.       /* Write as much as possible to the current block */
  733.  
  734.       if(block!=NULL)
  735.       {
  736.          block_length=block->length-block_pos;
  737.          write_length=MIN(remainder,block_length);
  738.          CopyMem(buffer,((UBYTE *)block)+sizeof(struct Block)+block_pos,
  739.             write_length);
  740.          remainder-=write_length;
  741.          buffer+=write_length;
  742.          block_pos+=write_length;
  743.  
  744.          /* Move on to next block if end of current block reached */
  745.  
  746.          if(write_length==block_length)
  747.          {
  748.             block=(struct Block *)((struct MinNode *)block)->mln_Succ;
  749. /*            block_length=block->length;*/
  750.             block_pos=0;
  751.          }
  752.       }
  753.       else
  754.          error=IoErr();
  755.    }
  756.  
  757.    /* Recalculate length of used portion of last block */
  758.  
  759.    end_block=(struct Block *)file->elements.mlh_TailPred;
  760.    if((block==end_block)&&(block_pos>file->end_length))
  761.    {
  762.       file->end_length=block_pos;
  763.       block=(struct Block *)((struct MinNode *)block)->mln_Succ;
  764.       block_pos=0;
  765.    }
  766.    else if((struct Block *)((struct MinNode *)block)->mln_Pred==end_block)
  767.       file->end_length=end_block->length;
  768.  
  769.    /* Update file size, volume size and current position */
  770.  
  771.    length-=remainder;
  772.    pos+=length;
  773.    if(pos>file_length)
  774.       file->length=pos;
  775.    opening->pos=pos;
  776.    opening->block=block;
  777.    opening->block_pos=block_pos;
  778.    handler->block_count+=file->block_count-block_count;
  779.  
  780.    /* Return number of bytes written */
  781.  
  782.    SetIoErr(error);
  783.    return length;
  784. }
  785.  
  786.  
  787. #if 0
  788. UPINT WriteData(struct Handler *handler,struct Opening *opening,
  789.    UBYTE *buffer,UPINT length)
  790. {
  791.    struct Block *block,*end_block;
  792.    struct Object *file;
  793.    UPINT block_pos,block_length,write_length,remainder=length,file_length,
  794.       block_count,pos;
  795.    LONG error=0;
  796.  
  797.    file=opening->file;
  798.    block_count=file->block_count;
  799.    file_length=file->length;
  800.    block=opening->block;
  801.    block_pos=opening->block_pos;
  802.  
  803.    while((remainder>0)&&(block!=NULL))
  804.    {
  805.       /* Add another block to the file if required */
  806.  
  807.       if(((struct MinNode *)block)->mln_Succ==NULL)
  808.       {
  809.          block=AddDataBlock(handler,opening->file,remainder);
  810.          file->end_length=0;
  811.       }
  812.  
  813.       /* Write as much as possible to the current block */
  814.  
  815.       if(block!=NULL)
  816.       {
  817.          block_length=block->length-block_pos;
  818.          write_length=MIN(remainder,block_length);
  819.          CopyMem(buffer,((UBYTE *)block)+sizeof(struct Block)+block_pos,
  820.             write_length);
  821.          remainder-=write_length;
  822.          buffer+=write_length;
  823.          block_pos+=write_length;
  824.  
  825.          /* Move on to next block if end of current block has been reached */
  826.  
  827.          if(write_length==block_length)
  828.          {
  829.             block=(struct Block *)((struct MinNode *)block)->mln_Succ;
  830.             block_length=block->length;
  831.             block_pos=0;
  832.          }
  833.       }
  834.       else
  835.          error=IoErr();
  836.    }
  837.  
  838.    /* Recalculate length of used portion of last block */
  839.  
  840.    end_block=(struct Block *)file->elements.mlh_TailPred;
  841.    if((block==end_block)&&(block_pos>file->end_length))
  842.       file->end_length=block_pos;
  843.    if((struct Block *)((struct MinNode *)block)->mln_Pred==end_block)
  844.       file->end_length=end_block->length;
  845.  
  846.    /* Update file size, volume size and current position */
  847.  
  848.    pos=opening->pos;
  849.    length-=remainder;
  850.    pos+=length;
  851.    if(pos>file_length)
  852.       file->length=pos;
  853.    opening->pos=pos;
  854.    opening->block=block;
  855.    opening->block_pos=block_pos;
  856.    handler->block_count+=file->block_count-block_count;
  857.  
  858.    /* Return number of bytes written */
  859.  
  860.    SetIoErr(error);
  861.    return length;
  862. }
  863. #endif
  864.  
  865.  
  866. /****i* ram.handler/LockObject *********************************************
  867. *
  868. *   NAME
  869. *    LockObject --
  870. *
  871. *   SYNOPSIS
  872. *    lock = LockObject(handler,object,
  873. *        access)
  874. *
  875. *    struct Lock *LockObject(struct Handler *handler,struct Object *,
  876. *        LONG);
  877. *
  878. *   FUNCTION
  879. *
  880. *   INPUTS
  881. *
  882. *   RESULT
  883. *
  884. *   EXAMPLE
  885. *
  886. *   NOTES
  887. *
  888. *   BUGS
  889. *
  890. *   SEE ALSO
  891. *
  892. ****************************************************************************
  893. *
  894. */
  895.  
  896. struct Lock *LockObject(struct Handler *handler,struct Object *object,
  897.    LONG access)
  898. {
  899.    struct Lock *lock;
  900.    LONG error,lock_access;
  901.  
  902.    object=GetRealObject(object);
  903.    lock=object->lock;
  904.  
  905.    if(lock==NULL)
  906.    {
  907.       lock=AllocMem(sizeof(struct Lock),MEMF_PUBLIC|MEMF_CLEAR);
  908.  
  909.       if(lock!=NULL)
  910.       {
  911.          object->lock=lock;
  912.  
  913.          ((struct FileLock *)lock)->fl_Key=(PINT)object;
  914.          ((struct FileLock *)lock)->fl_Access=access;
  915.          ((struct FileLock *)lock)->fl_Task=handler->proc_port;
  916.          ((struct FileLock *)lock)->fl_Volume=MKBADDR(handler->volume);
  917.       }
  918.       else
  919.          error=IoErr();
  920.    }
  921. /*#ifndef AMIGAOS*/
  922.    else
  923.    {
  924.       lock_access=((struct FileLock *)lock)->fl_Access;
  925.       if((access==ACCESS_WRITE)||(lock_access==ACCESS_WRITE))
  926.       {
  927.          lock=NULL;
  928.          error=ERROR_OBJECT_IN_USE;
  929.       }
  930.    }
  931. /*#endif*/
  932.  
  933.    if(lock!=NULL)
  934.    {
  935.       lock->lock_count++;
  936.       handler->lock_count++;
  937.    }
  938.  
  939.    SetIoErr(error);
  940.  
  941.    return lock;
  942. }
  943.  
  944.  
  945.  
  946. /****i* ram.handler/ExamineObject ******************************************
  947. *
  948. *   NAME
  949. *    ExamineObject --
  950. *
  951. *   SYNOPSIS
  952. *    success = ExamineObject(handler,object,
  953. *        info)
  954. *
  955. *    BOOL ExamineObject(struct Handler *,struct Object *,
  956. *        struct FileInfoBlock *);
  957. *
  958. *   FUNCTION
  959. *
  960. *   INPUTS
  961. *
  962. *   RESULT
  963. *
  964. *   EXAMPLE
  965. *
  966. *   NOTES
  967. *
  968. *   BUGS
  969. *
  970. *   SEE ALSO
  971. *
  972. ****************************************************************************
  973. *
  974. */
  975.  
  976. BOOL ExamineObject(struct Handler *handler,struct Object *object,
  977.    struct FileInfoBlock *info)
  978. {
  979.    BOOL success;
  980.    struct Object *next_object;
  981.    STRPTR s;
  982.    LONG entry_type;
  983.  
  984.    if(object==NULL)
  985.    {
  986.       object=(struct Object *)info->fib_DiskKey;
  987.       next_object=(APTR)((struct Node *)object)->ln_Succ;
  988.    }
  989.    else
  990.       next_object=(APTR)object->elements.mlh_Head;
  991.  
  992.    if(next_object!=NULL)
  993.    {
  994.       /* Fill in information from object */
  995.  
  996.       entry_type=((struct Node *)object)->ln_Pri;
  997.       info->fib_DirEntryType=entry_type;
  998.       info->fib_EntryType=entry_type;
  999.       s=((struct Node *)object)->ln_Name;
  1000.       CopyMem(MkBStr(s),&info->fib_FileName,StrSize(s));
  1001.       s=object->comment;
  1002.       if(s!=NULL)
  1003.          CopyMem(MkBStr(s),&info->fib_Comment,StrLen(s)+1);
  1004.       else
  1005.          info->fib_Comment[0]='\0';
  1006.       info->fib_NumBlocks=object->block_count;
  1007.  
  1008.       /* Fill in information from real object */
  1009.  
  1010.       object=GetRealObject(object);
  1011.  
  1012.       info->fib_Protection=object->protection;
  1013.       info->fib_Size=object->length;
  1014.       CopyMem(&object->date,&info->fib_Date,sizeof(struct DateStamp));
  1015.  
  1016.       /* Prepare for next examination */
  1017.  
  1018.       success=TRUE;
  1019.       info->fib_DiskKey=(PINT)next_object;
  1020.    }
  1021.    else
  1022.    {
  1023.       success=FALSE;
  1024.       SetIoErr(ERROR_NO_MORE_ENTRIES);
  1025.    }
  1026.  
  1027.    return success;
  1028. }
  1029.  
  1030.  
  1031.  
  1032. /****i* ram.handler/SetName ************************************************
  1033. *
  1034. *   NAME
  1035. *    SetName --
  1036. *
  1037. *   SYNOPSIS
  1038. *    success = SetName(handler,object,name)
  1039. *
  1040. *    BOOL SetName(struct Handler *,struct Object *,TEXT *);
  1041. *
  1042. *   FUNCTION
  1043. *
  1044. *   INPUTS
  1045. *
  1046. *   RESULT
  1047. *
  1048. *   EXAMPLE
  1049. *
  1050. *   NOTES
  1051. *
  1052. *   BUGS
  1053. *
  1054. *   SEE ALSO
  1055. *
  1056. ****************************************************************************
  1057. *
  1058. */
  1059.  
  1060. BOOL SetName(struct Handler *handler,struct Object *object,
  1061.    const TEXT *name)
  1062. {
  1063.    LONG error;
  1064.    const TEXT *p;
  1065.    TEXT ch;
  1066.    struct Locale *locale;
  1067.    PINT block_diff;
  1068.  
  1069.    error=0;
  1070.  
  1071.    /* Check name isn't too long */
  1072.  
  1073.    if(StrSize(name)>sizeof(((struct FileInfoBlock *)NULL)->fib_FileName))
  1074.       error=ERROR_INVALID_COMPONENT_NAME;
  1075.  
  1076.    /* Check name doesn't have any strange characters in it */
  1077.  
  1078.    locale=handler->locale;
  1079.    for(p=name;(ch=*p)!='\0';p++)
  1080.       if(!IsPrint(locale,ch)||IsCntrl(locale,ch)||(ch==':'))
  1081.          error=ERROR_INVALID_COMPONENT_NAME;
  1082.  
  1083.    /* Store new name */
  1084.  
  1085.    if(error==0)
  1086.    {
  1087.       block_diff=SetString(&((struct Node *)object)->ln_Name,name);
  1088.       if(block_diff==-1)
  1089.          error=IoErr();
  1090.       else
  1091.       {
  1092.          object->block_count+=block_diff;
  1093.          handler->block_count+=block_diff;
  1094.       }
  1095.    }
  1096.  
  1097.    /* Return success indicator */
  1098.  
  1099.    SetIoErr(error);
  1100.    return error==0;
  1101. }
  1102.  
  1103.  
  1104.  
  1105. /****i* ram.handler/FixLock ************************************************
  1106. *
  1107. *   NAME
  1108. *    FixLock --
  1109. *
  1110. *   SYNOPSIS
  1111. *    fixed_lock = FixLock(handler,lock)
  1112. *
  1113. *    struct Lock *FixLock(struct Handler *,struct Lock *);
  1114. *
  1115. *   FUNCTION
  1116. *
  1117. *   INPUTS
  1118. *
  1119. *   RESULT
  1120. *
  1121. *   EXAMPLE
  1122. *
  1123. *   NOTES
  1124. *
  1125. *   BUGS
  1126. *
  1127. *   SEE ALSO
  1128. *
  1129. ****************************************************************************
  1130. *
  1131. */
  1132.  
  1133. struct Lock *FixLock(struct Handler *handler,struct Lock *lock)
  1134. {
  1135.    if(lock==NULL)
  1136.       lock=handler->root_dir->lock;
  1137.  
  1138.    return lock;
  1139. }
  1140.  
  1141.  
  1142.  
  1143. /****i* ram.handler/AddDataBlock *******************************************
  1144. *
  1145. *   NAME
  1146. *    AddDataBlock --
  1147. *
  1148. *   SYNOPSIS
  1149. *    block = AddDataBlock(file,length)
  1150. *
  1151. *    struct Block *AddDataBlock(struct Object *,UPINT);
  1152. *
  1153. *   FUNCTION
  1154. *
  1155. *   INPUTS
  1156. *
  1157. *   RESULT
  1158. *
  1159. *   EXAMPLE
  1160. *
  1161. *   NOTES
  1162. *    Attempts to allocate a smaller block if the requested size cannot be
  1163. *    obtained.
  1164. *
  1165. *   BUGS
  1166. *
  1167. *   SEE ALSO
  1168. *
  1169. ****************************************************************************
  1170. *
  1171. */
  1172.  
  1173. struct Block *AddDataBlock(struct Handler *handler,struct Object *file,
  1174.    UPINT length)
  1175. {
  1176.    struct Block *block;
  1177.    UPINT alloc_size;
  1178.    ULONG limit;
  1179.  
  1180.    /* Ensure block size is within limits */
  1181.  
  1182.    alloc_size=sizeof(struct Block)+length;
  1183.  
  1184.    limit=handler->max_block_size;
  1185.    if(alloc_size>limit)
  1186.       alloc_size=limit;
  1187.  
  1188.    limit=handler->min_block_size;
  1189.    if(alloc_size<limit)
  1190.       alloc_size=limit;
  1191.  
  1192.    /* Allocate a multiple of the memory block size */
  1193.  
  1194.    block=NULL;
  1195.    while((block==NULL)&&(alloc_size>=limit))
  1196.    {
  1197.       alloc_size=((alloc_size-1)&(~MEM_BLOCKMASK))+MEM_BLOCKSIZE;
  1198.       block=AllocMem(alloc_size,MEMF_ANY);
  1199.       if(block==NULL)
  1200.          alloc_size>>=1;
  1201.    }
  1202.  
  1203.    /* Add the block to the end of the file */
  1204.  
  1205.    if(block!=NULL)
  1206.    {
  1207.       AddTail((struct List *)&file->elements,(struct Node *)block);
  1208.       block->length=alloc_size-sizeof(struct Block);
  1209.       file->block_count+=alloc_size>>MEM_BLOCKSHIFT;
  1210.    }
  1211.    else
  1212.       SetIoErr(ERROR_DISK_FULL);
  1213.  
  1214.    /* Return the new block */
  1215.  
  1216.    return block;
  1217. }
  1218.  
  1219.  
  1220.  
  1221. /****i* ram.handler/FreeDataBlock ******************************************
  1222. *
  1223. *   NAME
  1224. *    FreeDataBlock --
  1225. *
  1226. *   SYNOPSIS
  1227. *    FreeDataBlock(file,block)
  1228. *
  1229. *    VOID FreeDataBlock(struct Object *,struct Block *);
  1230. *
  1231. *   FUNCTION
  1232. *
  1233. *   INPUTS
  1234. *
  1235. *   RESULT
  1236. *
  1237. *   EXAMPLE
  1238. *
  1239. *   NOTES
  1240. *
  1241. *   BUGS
  1242. *
  1243. *   SEE ALSO
  1244. *
  1245. ****************************************************************************
  1246. *
  1247. */
  1248.  
  1249. VOID FreeDataBlock(struct Object *file,struct Block *block)
  1250. {
  1251.    UPINT alloc_size;
  1252.  
  1253.    if(block!=NULL)
  1254.    {
  1255.       alloc_size=sizeof(struct Block)+block->length;
  1256.       file->block_count-=alloc_size>>MEM_BLOCKSHIFT;
  1257.       FreeMem(block,alloc_size);
  1258.    }
  1259.  
  1260.    return;
  1261. }
  1262.  
  1263.  
  1264.  
  1265. /****i* ram.handler/GetRealObject ******************************************
  1266. *
  1267. *   NAME
  1268. *    GetRealObject --
  1269. *
  1270. *   SYNOPSIS
  1271. *    real_object = GetRealObject(object)
  1272. *
  1273. *    struct Object *GetRealObject(struct Object *);
  1274. *
  1275. *   FUNCTION
  1276. *
  1277. *   INPUTS
  1278. *
  1279. *   RESULT
  1280. *
  1281. *   EXAMPLE
  1282. *
  1283. *   NOTES
  1284. *
  1285. *   BUGS
  1286. *
  1287. *   SEE ALSO
  1288. *
  1289. ****************************************************************************
  1290. *
  1291. */
  1292.  
  1293. struct Object *GetRealObject(struct Object *object)
  1294. {
  1295.    struct MinNode *node,*pred;
  1296.  
  1297.    /* Get first node in list */
  1298.  
  1299.    node=&object->hard_link;
  1300.    if(node->mln_Pred!=NULL)
  1301.    {
  1302.       while((pred=node->mln_Pred)!=NULL)
  1303.          node=pred;
  1304.       node=node->mln_Succ;
  1305.    }
  1306.  
  1307.    /* Get object from node address */
  1308.  
  1309.    object=HARDLINK(node);
  1310.    return object;
  1311. }
  1312.  
  1313.  
  1314.  
  1315. /****i* ram.handler/GetRealObject ******************************************
  1316. *
  1317. *   NAME
  1318. *    GetBlockLength --
  1319. *
  1320. *   SYNOPSIS
  1321. *    length = GetBlockLength(file,block)
  1322. *
  1323. *    UPINT GetBlockLength(struct Object *,struct Block *);
  1324. *
  1325. *   FUNCTION
  1326. *
  1327. *   INPUTS
  1328. *
  1329. *   RESULT
  1330. *
  1331. *   EXAMPLE
  1332. *
  1333. *   NOTES
  1334. *
  1335. *   BUGS
  1336. *
  1337. *   SEE ALSO
  1338. *
  1339. ****************************************************************************
  1340. *
  1341. */
  1342.  
  1343. UPINT GetBlockLength(struct Object *file,struct Block *block)
  1344. {
  1345.    UPINT length;
  1346.  
  1347.    if(block==(APTR)file->elements.mlh_TailPred)
  1348.       length=file->end_length;
  1349.    else if(((struct MinNode *)block)->mln_Succ==NULL)
  1350.       length=0;
  1351.    else
  1352.       length=block->length;
  1353.  
  1354.    return length;
  1355. }
  1356.  
  1357.  
  1358.  
  1359.